/// <source>
/// <name>Hemi.transaction</name>
/// <project>
/// 	<name>Hemi JavaScript Framework</name>
/// 	<url-title>Hemi JavaScript Framework Project</url-title>
/// 	<url>/Hemi/</url>
/// </project>
///
/// <package>
///	<path>Hemi.transaction</path>
///	<library>Hemi</library>
///	<description>The Transaction Service provides an object-level communication bus. Unlike events, delegates, and message subscriptions and publications, the transaction service coordinates disimilar objects on a common band.  Non Framework Objects may be decorated with the Transaction Participant API, and allow cross-Framework coordination.</description>
/// <static-class>
///		<name>service</name>
///		<description>Static instance of the serviceImpl class.</description>
///		<version>%FILE_VERSION%</version>
/// </static-class>
/// <static-class>
///		<name>TransactionParticipant</name>
///		<description>This static class describes the interface an object must expose to participate in the TransactionService.  A participant must be registered with the ObjectRegistry.  The addServiceAPI method may be used to instrument this API for quick access to the service.</description>
///		<method>
///			<name>doTransaction</name>
///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
///			<param name = "p" type = "TransactionPacket">The packet being served.</param>
///			<return-value name = "z" type = "boolean">Always returns false.</return-value>
///			<description>Processes the served transaction packet.</description>
///		</method>
///		<method>
///			<name>startTransaction</name>
///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
///			<param name = "p" type = "TransactionPacket">The packet for this transaction.</param>
///			<description>Starts the transaction for the specified packet.</description>
///		</method>
///		<method>
///			<name>endTransaction</name>
///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
///			<param name = "p" type = "TransactionPacket">The packet for this transaction.</param>
///			<description>Ends the transaction for the specified packet.</description>
///		</method>
///		<version>%FILE_VERSION%</version>
/// </static-class>
/// <class>
///		<name>TransactionPacket</name>
///		<version>%FILE_VERSION%</version>
///		<description>This is an abstract class generated by the TransactionService. It has no public initializer or constructor.</description>
///		<property type = "String" get = "1">
///			<name>service_id</name>
///			<description>The unique identifier of the service to which this packet belongs.</description>
///		</property>
///		<property type = "String" get = "1">
///			<name>packet_id</name>
///			<description>The unique identifer of the packet.</description>
///		</property>
///		<property type = "String" get = "1">
///			<name>packet_name</name>
///			<description>The name of the packet.</description>
///		</property>
///		<property type = "hash" get = "1">
///			<name>participants</name>
///			<description>Hash of object identifiers that are participating in the transaction for this packet. The hash key is the object identifier, and the hash value is the participant state.  State values are: 0 = not participating / transaction ended, 1 = participating, 2 = participated and completed with a positive (true) response.</description>
///		</property>
///		<property type = "int" get = "1">
///			<name>participant_count</name>
///			<description>Number of participants currently using this packet.</description>
///		</property>
///		<property type = "int" get = "1" set = "1">
///			<name>packet_state</name>
///			<description>Variable use property.</description>
///		</property>
///		<property type = "int" get = "1">
///			<name>serve_type</name>
///			<description>The type of service this packet will receive.  1 indicates the packet will be served untill all participants return true from <i>doTransaction</i>.  2 indicates the packet is only served once.</description>
///		</property>
///		<method>
///			<name>setBlockStartTransaction</name>
///			<param name = "b" type = "boolean">Bit indicating whether the packet is blocked from being served during <i>startTransaction</i>.</param>
///			<description>Specifies whether the packet should be served during <i>startTransaction</i>.</description>
///		</method>
///		<method>
///			<name>setBlockServeTransaction</name>
///			<param name = "b" type = "boolean">Bit indicating whether the packet is blocked from being served during <i>serveTransaction</i>.</param>
///			<description>Specifies whether the packet should be served during <i>serveTransaction</i>.</description>
///		</method>
///		<method>
///			<name>setBlockEndTransaction</name>
///			<param name = "b" type = "boolean">Bit indicating whether the packet is blocked from being served during <i>endTransaction</i>.</param>
///			<description>Specifies whether the packet should be served during <i>endTransaction</i>.</description>
///		</method>
///		<method>
///			<name>setServeType</name>
///			<param name = "i" type = "int">The type of service this packet will receive.  1 indicates the packet will be served untill all participants return true from <i>doTransaction</i>.  2 indicates the packet is only served once.</param>
///			<description>Sets the packet serve type.</description>
///		</method>
///		<property type = "boolean" get = "1">
///			<name>is_open</name>
///			<description>Bit indicating whether the packet is open.</description>
///		</property>
///		<property type = "boolean" get = "1">
///			<name>is_finalized</name>
///			<description>Bit indicating whether the packet has been finalized.</description>
///		</property>
///		<property type = "int" get = "1" set = "1">
///			<name>errors</name>
///			<description>Variable use property.</description>
///		</property>
///		<property type = "String" get = "1">
///			<name>owner_id</name>
///			<description>Identifier of the registered object that owns the packet.</description>
///		</property>
///		<property type = "variant" get = "1" set = "1">
///			<name>data</name>
///			<description>The packet data.</description>
///		</property>

/// </class>

(function () {

	HemiEngine.include("hemi.object");
	HemiEngine.include("hemi.util");
	HemiEngine.include("hemi.util.logger");
	HemiEngine.namespace("transaction", HemiEngine, {
		service: null,
		/// <static-class>
		///		<name>transaction</name>
		///		<description>Static instance of the serviceImpl class.</description>
		///		<version>%FILE_VERSION%</version>

		///		<method>
		///			<name>addServiceAPI</name>
		///			<param name = "o" type = "Object">Object onto which to inject helper methods for working with transactions.</param>
		/// 		<return-value name = "b" type = "boolean">Bit indicating whether the service API was injected where otherwise not defined.</return-value>
		///			<description>Injects the required API for working with transactions onto the target object.</description>
		///		</method>
		addServiceAPI: function (o) {


			if (!DATATYPES.TO(o) || !DATATYPES.TO(o.properties)) {
				HemiEngine.logWarning("Object is null or does not define a properties hash");
				return 0;
			}
			///		<method virtual = "1">
			///			<name>_handle_transaction</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet being served.</param>
			///			<description>Processes the served transaction packet.</description>
			///		</method>

			///		<method virtual = "1">
			///			<name>_handle_begin_transaction</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet being served.</param>
			///			<description>Invoked when the transaction for the specified packet begins.</description>
			///		</method>

			///		<method virtual = "1">
			///			<name>_handle_end_transaction</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet being served.</param>
			///			<description>Invoked when the transaction for the specified packet ends.</description>
			///		</method>

			///		<method virtual = "1">
			///			<name>_handle_packettype</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet being served.</param>
			///			<description>Processes the served transaction packet for the specified type. IE if a packet has the type 'custompacket', then you can define a method named <i>_handle_custompacket</i></description>
			///		</method>

			///		<method virtual = "1">
			///			<name>getPacket</name>
			///			<return-value name = "p" type = "TransactionPacket">TransactionPacket object.</return-value>
			///			<description>Returns the transaction packet associated with this component.</description>
			///		</method>
			if (!DATATYPES.TF(o.getPacket))
				o.getPacket = function (n) {
					var _t = HemiEngine.transaction.service;
					if (n) return _t.getPacketByName(n);
					else return _t.getPacket(this.properties.PacketId);
				};
			///		<method virtual = "1">
			///			<name>startTransaction</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet for this transaction.</param>
			///			<return-value name = "z" type = "boolean">Always returns true.</return-value>
			///			<description>Starts the transaction for the specified packet. Automatically invokes <i>_handle_begin_transaction</i> if defined.</description>
			///		</method>
			if (!DATATYPES.TF(o.startTransaction))
				o.startTransaction = function (s, p) {
					/*
					s = service
					p = packet
					*/
					var 
						_m = HemiEngine.message.service,
						t = this;

					if (typeof t._handle_begin_transaction == DATATYPES.TYPE_FUNCTION) t._handle_begin_transaction(s, p);


					_m.sendMessage("Start transaction " + p.packet_name + " for " + t.object_type, "200.1");


					return 1;
				};
			///		<method virtual = "1">
			///			<name>endTransaction</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet for this transaction.</param>
			///			<return-value name = "z" type = "boolean">Always returns true.</return-value>
			///			<description>Ends the transaction for the specified packet. Automatically invokes <i>_handle_end_transaction</i> if defined.</description>
			///		</method>
			if (!DATATYPES.TF(o.endTransaction))
				o.endTransaction = function (s, p) {
					/*
					s = service
					p = packet
					*/
					var t = this;
					if (typeof t._handle_end_transaction == DATATYPES.TYPE_FUNCTION) t._handle_end_transaction(s, p);
					HemiEngine.message.service.sendMessage("End transaction " + p.packet_name + " for " + t.object_type, "200.1");
					return 1;
				};
			///		<method virtual = "1">
			///			<name>doTransaction</name>
			///			<param name = "s" type = "TransactionService">The TransactionService object handling this transaction.</param>
			///			<param name = "p" type = "TransactionPacket">The packet being served.</param>
			///			<return-value name = "z" type = "boolean">Always returns false.</return-value>
			///			<description>Processes the served transaction packet.  Automatically invokes <i>_handle_transaction</i>, if it was defined.  Also will invoke <i>_handle_packettype</i> if defined.  IE if a packet has the type 'custompacket', then you can define a method named <i>_handle_custompacket</i></description>
			///		</method>
			if (!DATATYPES.TF(o.doTransaction))
				o.doTransaction = function (s, p) {
					/*
					s = service
					p = packet
					*/
					var t = this, q, qh, x = 0, y = 0;

					if (typeof t._handle_transaction == DATATYPES.TYPE_FUNCTION) x = t._handle_transaction(s, p);
					q = p.data.type;
					qh = '_handle_' + q;
					if (q && typeof t[qh] == DATATYPES.TYPE_FUNCTION) y = t[qh](s, p);
					(t.logDebug ? t : HemiEngine).logDebug("Do Transaction for " + t.object_id + " on target " + qh);
					return y;
					///(x || y);
				};

			///	<method virtual = "1">
			///		<name>serveTransaction</name>
			///		<param name = "t" type = "variant">Variant value used to identify the type of the packet.</param>
			///		<param name = "s" type = "variant">Variant value used to identify the source of the packet.</param>
			///		<param name = "b" type = "boolean">Bit indicating whether the packet should be served to the owner.</param>
			///		<param name = "n" type = "String">Packet name.</param>
			///		<return-value name = "z" type = "boolean">Returns true if a packet exists and was served, false otherwise.</return-value>
			///		<description>Serves the transaction packet to transaction participants.</description>
			///	</method>
			if (!DATATYPES.TF(o.serveTransaction))
				o.serveTransaction = function (v, r, b, n) {
					/*
					v = variant value
					r = variant value
					b = bool; serve to owner
					n = alternate packet name
					*/
					var _t = HemiEngine.transaction.service, p, t = this;
					p = t.getPacket(n);
					/// alert(n + ":" + p.participants.length);
					if (p) {
						if (p.data.type && p.data.type != v) {
							(t.logError ? t : HemiEngine).logWarning("Packet type override: " + p.data.type + " -> " + v);
						}
						p.data.type = v;
						p.data.src = r;
						/*
						_t.logDebug("Serve Transaction " + p.packet_name);
						*/
						_t.serveTransaction(p, t.object_id, (!b));
						return 1;
					}
					return 0;
				};
			///	<method virtual = "1">
			///		<name>joinTranactionPacket</name>
			///		<param name = "s" type = "String">The packet name.</param>
			///		<return-value name = "sPacketId" type = "String">The transaction packet identifier.</return-value>
			///		<description>Joins the object to the packet, and returns the packet identifier.</description>
			///	</method>
			if (!DATATYPES.TF(o.joinTransactionPacket))
				o.joinTransactionPacket = function (n) {
					var _t = HemiEngine.transaction.service, p, t = this, i, b = 1;
					if (!n && t.properties) n = t.properties.TransactionName;
					if (!n) {
						HemiEngine.logWarning('Invalid packet name: ' + n);
						return 0;
					}
					/* Get any packets with the specified name */
					p = _t.getPacketByName(n);
					if (p) {
						i = p.packet_id;
						p.setBlockStartTransaction(false);
						b = _t.addTransactionParticipant(t, p);
					}
					else {
						i = _t.openTransaction(n, t, { type: 0, src: 0, data: 0 });
					}
					if (t.properties.PacketId) {
						/// alert("Warn packet overwrite: " + t.properties.PacketId + " with " + i);
						(t.logWarning ? t : HemiEngine).logWarning("Packet identifier is being overwritten: " + t.properties.PacketId + " to " + i);
					}
					t.properties.PacketId = i;

					return (!b ? 0 : i);
				};
			///	<method virtual = "1">
			///		<name>removeFromTransactionPacket</name>
			///		<param name = "s" type = "String">The packet name.</param>
			///		<return-value name = "sPacketId" type = "String">The transaction packet identifier.</return-value>
			///		<description>Removes the object from the packet.</description>
			///	</method>
			if (!DATATYPES.TF(o.removeFromTransactionPacket))
				o.removeFromTransactionPacket = function (n) {
					var _t = HemiEngine.transaction.service, p, t = this, i, b = 1;
					p = this.getPacket(n);
					if (!p)
						return b;
					else
						b = _t.removeTransactionParticipant(t, p);
					return b;
				};
			return 1;
		},
		/// </static-class>
		/// <class>
		/// 		<name>serviceImpl</name>
		///			<description>A class for managing communication between objects implementing the TransactionParticipant API, and using TransactionPacket objects.</description>
		///			<version>%FILE_VERSION%</version>
		///				<method>		
		/// 			<name>isPacket</name>
		/// 			<param name = "i" type = "variant">Name or index of the TransactionPacket object..</param>
		/// 			<return-value name = "b" type = "boolean">Bit indicating whether the specified object name exists.</return-value>
		/// 			<description>Returns true if the specified name exists.</description>
		/// 			</method>
		/// 			<method>
		/// 			<name>getPackets</name>
		/// 			<return-value name = "a" type = "array">Array of TransactionPacket objects.</return-value>
		/// 			<description>Returns an array of TransactionPacket objects.</description>
		///				 </method>
		/// 			<method>
		/// 			<name>getPacket</name>
		/// 			<param name = "i" type = "int">Index of the TransactionPacket object..</param>
		/// 			<return-value name = "e" type = "TransactionPacket">XHTMLForm object.</return-value>
		/// 			<description>Returns the specified TransactionPacket object.</description>
		/// 			</method>
		///				 <method>
		/// 			<name>getPacketByName</name>
		/// 			<param name = "n" type = "String">Name of the element.</param>
		/// 			<return-value name = "e" type = "TransactionPacket">TransactionPacket object.</return-value>
		/// 			<description>Returns the specified TransactionPacket object.</description>
		/// 			</method>
		serviceImpl: function () {
			var t = this;

			t.objects = {
				registered_objects: [],
				registered_objects_map: []
			};
			t.properties = {
				auto_serve: 0,
				packet_id_counter: 0,
				packet_id_label: "hemi.transaction"
			};
			///		<method>
			///			<name>sigterm</name>
			///			<description>Sends a termination signal to the service, and closes all open packets.</description>
			///		</method>
			t.sigterm = function () {
				var t = this, _p, a, i=0;
				_p = t.objects;
				if (t.ready_state != 5) {
					_p.registered_objects = [];
					_p.registered_objects_map = [];

					a = _p.packets;
					for (;i < a.length; i++){
						if(a[i]) t.closeTransaction(a[i].packet_id);
					}
					t.clearPackets();

				}
			};
			///		<method>
			///			<name>getRegisteredObjects</name>
			///			<description>Returns an array of object identifiers that are registered with the TransactionService.</description>
			///			<return-value type = "array" name = "a">Array of object identifiers</return-value>
			///		</method>	
			t.getRegisteredObjects = function () {
				return this.objects.registered_objects;
			};

			///		<method>
			///			<name>getRegisteredObjectsMap</name>
			///			<description>Returns a hashmap of object identifiers and the index into the registered objects array.</description>
			///			<return-value type = "array" name = "a">Hashmap of object identifiers</return-value>
			///		</method>
			t.getRegisteredObjectsMap = function () {
				return this.objects.registered_objects_map;
			};

			///		<method>
			///			<name>canRegister</name>
			///			<param name = "o" type = "object">Object to test whether or not it can be registered.</param>
			///			<description>Tests an object to determine if it can be registered.</description>
			///			<return-value type = "boolean" name = "b">True if the object can be registered, otherwise false.</return-value>
			///		</method>	
			t.canRegister = function (o) {
				var _o = HemiEngine.registry.service;
				if (

					!_o.isRegistered(o.object_id)
					||

					!DATATYPES.TF(o.doTransaction)
					||
					!DATATYPES.TF(o.startTransaction)
					||
					!DATATYPES.TF(o.endTransaction)

				) {
					return 0;
				}
				return 1;
			};

			///		<method>
			///			<name>isRegistered</name>
			///			<param name = "o" type = "object">Object to test whether or not it is registered.</param>
			///			<description>Returns whether an object is registered..</description>
			///			<return-value type = "boolean" name = "b">True if the object is registered, otherwise false.</return-value>
			///		</method>
			t.isRegistered = function (o) {
				var _p = t.objects;
				if (
					DATATYPES.TO(o) && o != null
					&&
					DATATYPES.TN(_p.registered_objects_map[o.object_id])
					&&
					_p.registered_objects[_p.registered_objects_map[o.object_id]]
				) {
					return 1;
				}
				return 0;
			};

			///		<method>
			///			<name>register</name>
			///			<param name = "o" type = "object">Object to register with the TransactionService.</param>
			///			<param name = "b" type = "boolean" optional = "1">Bit indicating the object should be instrumented with the transaction API.</param>
			///			<description>Registers an object with the transaction service.</description>
			///			<return-value type = "boolean" name = "b">True if the object was registered, otherwise false.</return-value>
			///		</method>
			t.register = function (o, b) {
				/*
				o = object to register
				b = Auto Instrument Required API
				*/
				var _p = t.objects, _m = HemiEngine.message.service;
				if (t.isRegistered(o)) {
					_m.sendMessage("Object " + o.object_type + " is already registered with transaction service", "511.4");
					return 0;
				}
				if (b) HemiEngine.transaction.addServiceAPI(o);
				if (
					!t.canRegister(o)
					||
					o.object_type == "transaction_service"
				) {
					_m.sendMessage("Unable to register object " + o.object_type + " with transaction service", "511.4");
					return 0;
				}
				_p.registered_objects_map[o.object_id] = _p.registered_objects.length;
				_p.registered_objects[_p.registered_objects.length] = o.object_id;


				return 1;
			};

			///		<method>
			///			<name>unregister</name>
			///			<param name = "o" type = "object">Object to register with the TransactionService.</param>
			///			<description>Unregisters an object with the transaction service.</description>
			///			<return-value type = "boolean" name = "b">True if the object was unregistered, otherwise false.</return-value>
			///		</method>
			t.unregister = function (o) {
				var _p = t.objects, _m = HemiEngine.message.service;
				if (!t.isRegistered(o))
					return 0;

				t.removeTransactionParticipants(o);

				_p.registered_objects[_p.registered_objects_map[o.object_id]] = 0;
				delete _p.registered_objects_map[o.object_id];


				return 1;
			};

			///		<method>
			///			<name>removeTransactionParticipants</name>
			///			<param name = "o" type = "TransactionParticipant">Object that is registered with the TransactionService.</param>
			///			<description>Removes object from all transaction participations.</description>
			///		</method>
			t.removeTransactionParticipants = function (o) {

				p = t.objects.packets, i = 0;
				for (; i < p.length; ) t.removeTransactionParticipant(o, p);

			};

			///		<method>
			///			<name>addTransactionParticipant</name>
			///			<param name = "o" type = "TransactionParticipant">Object that is registered with the TransactionService.</param>
			///			<param name = "p" type = "TransactionPacket">TransactionPacket with which the specified object should participate.</param>
			///			<description>Adds an object to participate with the specified TransactionPacket.</description>
			///			<return-value type = "boolean" name = "b">True if the object is participating with the packet, otherwise false.</return-value>
			///		</method>
			t.addTransactionParticipant = function (o, p) {

				var _m = HemiEngine.message.service;
				/// HemiEngine.log("Add P: " + t.isRegistered(o) + " / " + t.isPacket(p) + " / " + p.participants[o.object_id]);
				if (

					t.isRegistered(o)
					&&

					t.isPacket(p)
					&&

					!p.participants[o.object_id]
				) {
					p.participants[o.object_id] = 1;
					p.participant_count++;

					if (!p.block_start_transaction) o.startTransaction(t, p);

					return 1;
				}
				return 0;
			};

			///		<method>
			///			<name>removeTransactionParticipant</name>
			///			<param name = "o" type = "TransactionParticipant">Object that is registered with the TransactionService.</param>
			///			<param name = "p" type = "TransactionPacket">TransactionPacket with which the specified object is participating.</param>
			///			<description>Removes an object from participating with the specified TransactionPacket.</description>
			///			<return-value type = "boolean" name = "b">True if the object was removed from participating with the packet, otherwise false.</return-value>
			///		</method>	
			t.removeTransactionParticipant = function (o, p) {

				var _m = HemiEngine.message.service;

				if (

					t.isRegistered(o)
					&&

					t.isPacket(p)
					&&

					p.participants[o.object_id]
				) {
					delete p.participants[o.object_id];
					p.participant_count--;

					return 1;
				}
				return 0;
			};

			///		<method>
			///			<name>serveTransaction</name>
			///			<param name = "p" type = "TransactionPacket">TransactionPacket with which the specified object is participating.</param>
			///			<param name = "i" type = "String" optional = "1" default = "owner id">Identifier of the object that should act as the controller of the packet.  Defaults to the packet owner.</param>
			///			<param name = "b" type = "boolean" optional = "1" default = "false">Skip serving the packet to the controller.</param>
			///			<description>Serves the specified TransactionPacket to its participants.</description>
			///			<return-value type = "boolean" name = "b">True if the packet was served, otherwise false.</return-value>
			///		</method>	
			t.serveTransaction = function (p, x, b) {

				var _m = HemiEngine.message.service,
					_o = HemiEngine.registry.service,
					o, a, i, d, r
				;

				if (t.isPacket(p)) {

					if (!p.is_open || !p.participant_count) return 0;

					if (DATATYPES.TU(x)) x = p.owner_id;
					a = p.participants;

					if (
						x
						&&
						_o.isRegistered(x)
						&&
						!b
						&&
						(
							(p.serve_type == 1 && a[x] != 2)
							||
							(p.serve_type == 2 && !a[x])
						)
					) {

						o = _o.getObject(x);
						if (t.isRegistered(o) && a[o.object_id]) {
							r = (o.doTransaction(t, p) ? 1 : 0);
							if (r && p.serve_type == 1) a[x] = 2;
						}
					}
					if (!x || !p.block_serve_transaction) {
						for (i in a) {
							d = a[i];

							if (
								d
								&&
								(
									(p.serve_type == 1 && d != 2)
									||
									(p.serve_type == 2 && !d)
								)
								&&
								_o.isRegistered(i)
								&&
								i != x
							) {
								o = _o.getObject(i);
								if (t.isRegistered(o)) {
									r = (o.doTransaction(t, p) ? 1 : 0);
									if (r && p.serve_type == 1) a[i] = 2;
								}
								/*
								else {
								t.logWarning("Skip serve " + p.packet_name+ " because o=" + i + " is not a registered object");
								}
								*/
							}
							/*
							else {
							t.logWarning("Skip serve " + p.packet_name + " because a[i]=" + d + " for i=" + i + " and x=" + x + " and type=" + p.serve_type);
							}
							*/
						}
					}
					/*
					else {
					t.logWarning("Skip serve " + p.packet_name + "  because x=" + x + " or b=" + p.block_serve_transaction);
					}
					*/
					r = 1;


					for (i in a) {
						if (
							(p.serve_type == 1 && a[i] != 2)
							||
							(p.serve_type == 2 && !a[i])
						) {
							r = 0;
							break;
						}
					}
					if (r) t._stopTransaction(p);

					return 1;
				}
				else {
					_m.sendMessage("Invalid transaction packet.", "511.4");
				}
				return 0;
			};

			t._stopTransaction = function (p) {
				var _m = HemiEngine.message.service,
					_o = HemiEngine.registry.service,
					a, i, o
				;
				if (t.isPacket(p)) {
					if (p.is_open) {
						a = p.participants;
						p.is_open = 0;
						if (
							p.owner_id
							&&
							_o.isRegistered(p.owner_id)
						) {
							o = _o.getObject(p.owner_id);
							o.endTransaction(t, p);
						}
						if (!p.owner_id || !p.block_end_transaction) {
							for (i in a) {
								if (p.owner_id != i) {
									o = _o.getObject(i);
									if (o != null) {
										o.endTransaction(t, p);
									}
									else {
										_m.sendMessage("Null object reference " + i, "540.4");
									}
								}

								a[i] = 0;

							}
						}

						p.stop_transaction = HemiEngine.util.getDate();
						p.is_finalized = 1;

						if (DATATYPES.TF(p.handler))
							p.handler(t, p);


					}
					else {
						_m.sendMessage("Transaction packet is not open.", "200.4");
					}



				}
				else {
					_m.sendMessage("Invalid transaction packet.", "200.4");
				}

			};

			t._startTransaction = function (p, o) {

				var n, a = t.objects.registered_objects, c;

				if (DATATYPES.TO(p)) {

					o.block_start_transaction = 1;
					v =
						o.participants[p.object_id] =
							(p.startTransaction(t, o) ? 1 : 0);

					o.participant_count += v;

				}

				if (o.participant_count) {
					o.start_transaction = HemiEngine.util.getDate();
					o.is_open = 1;
					return 1;

				}

				return 0;

			};

			///		<method>
			///			<name>closeTransaction</name>
			///			<param name = "i" type = "String">Name of the TransactionPacket.</param>
			///			<description>Closes the transaction represented by the specified TransactionPacket.</description>
			///		</method>	
			t.closeTransaction = function (i) {

				var _p = t.objects, o, _m = HemiEngine.message.service;
				o = t.getPacket(i);
				if (t.isPacket(o)) {
					t.removePacket(o);
				}
				else {
					_m.sendMessage("Invalid packet id " + i, "200.4");
				}
			};

			///		<method internal = "1">
			///			<name>newTransactionPacket</name>
			///			<param name = "i" type = "String">Packet identifier.</param>
			///			<param name = "n" type = "String">Packet name.</param>
			///			<param name = "o" type = "String">Owner id.</param>
			///			<param name = "v" type = "object">Variant data.</param>
			///			<param name = "f" type = "function">Packet finalization handler.</param>
			///			<description>Creates a new TransactionPacket.</description>
			///			<return-value type = "TransactionPacket" name = "p">A new TransactionPacket.</return-value>
			///		</method>
			t.newTransactionPacket = function (i, n, o, v, f) {
				var p = {
					service_id: t.object_id,
					packet_id: i,
					packet_name: n,
					participants: [],
					participant_count: 0,
					packet_state: 0,

					block_start_transaction: 0,
					block_serve_transaction: 0,
					block_end_transaction: 0,

					serve_type: 1,
					setBlockStartTransaction: function (b) { this.block_start_transaction = (b ? 1 : 0); },
					setBlockServeTransaction: function (b) { this.block_serve_transaction = (b ? 1 : 0); },
					setBlockEndTransaction: function (b) { this.block_end_transaction = (b ? 1 : 0); },
					setServeType: function (i) { this.block_serve_transaction = (!isNaN(i) ? i : 0); },

					start_transaction: 0,

					stop_transaction: 0,

					is_open: 0,
					is_finalized: 0,
					errors: 0,
					owner_id: o,
					data: v,
					handler: f
				};
				HemiEngine.prepareObject("transaction_packet", "%FILE_VERSION%", 1, p);
				return p;
			};

			///		<method>
			///			<name>openTransaction</name>
			///			<param name = "n" type = "String">Name of the transaction.</param>
			///			<param name = "p" type = "TransactionParticipant" optional="1">Parent object.</param>
			///			<param name = "d" type = "variant" optional="1">Data associated with the transaction.</param>
			///			<param name = "f" type = "function" optional="1">Function to invoke when transaction completes and the TransactionPacket is finalized.</param>
			///			<description>Opens a new transaction and returns the TransactionPacket identifier.</description>
			///			<return-value type = "String" name = "i">Identifier of the new TransactionPacket.</return-value>
			///		</method>	
			t.openTransaction = function (n, p, d, f) {

				var i,
					o,
					c,
					_p = t.objects,
					_s = t.properties,
					_m = HemiEngine.message.service
				;


				i = _s.packet_id_label + ":" + (++_s.packet_id_counter);

				if (DATATYPES.TU(n)) n = i;
				if (DATATYPES.TU(d)) d = 0;
				if (DATATYPES.TU(f)) f = 0;

				if (DATATYPES.TO(p)) {
					if (!t.isRegistered(p)) {
						_m.sendMessage("Invalid transaction owner.", "200.4");
						return 0;
					}
				}
				else
					p = 0;



				if (
					DATATYPES.TO(t.getPacketByName(n))
					&&
					t.getPacketByName(n).is_open
				) {
					_m.sendMessage("Transaction " + n + " is already open.", "200.4");
					return 0;
				}

				o = t.newTransactionPacket(i, n, p.object_id, d, f);

				t.addNewPacket(o, n, i);

				if (t._startTransaction(p, o)) {

					if (_s.auto_serve) t.serveTransaction(o);
				}

				else
					_m.sendMessage("Transaction " + n + " was not opened.", "200.4");


				return i;

			};
			HemiEngine.object.addObjectAccessor(t, "packet");
			HemiEngine.prepareObject("transaction_service", "%FILE_VERSION%", 1, t);
			HemiEngine.util.logger.addLogger(t, "Transaction Service", "Transaction Service", "500");
			t.ready_state = 4;
		}
	}, 1);
} ());

/// </class>
/// </package>
/// </source>